/**
 * Copyright 2014 opencxa.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.cxa.rpc.cloud.server.components.authentication;

import java.util.List;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.cxa.rpc.cloud.server.CloudServer;
import org.cxa.rpc.cloud.server.DeviceProxy;
import org.cxa.rpc.cloud.server.components.authentication.DatabaseManager.DatabaseManagerException;
import org.cxa.rpc.messages.RpcMessage;
import org.cxa.rpc.provider.Component;
import org.cxa.rpc.provider.RpcCommand;
import org.cxa.rpc.provider.RpcException;
import org.cxa.rpc.provider.RpcCommand.RestrictionType;


/**
 * @author Christopher Armenio
 *
 */
public class AuthenticationComponent extends Component
{	
	private final Logger logger;
	private final DatabaseManager dbManager;
	
	
	public AuthenticationComponent()
	{
		super("auth");
		this.logger = LogManager.getLogger(this.toString());
		
		this.dbManager = CloudServer.getSingleton().getDatabaseManager();
	}
	
	
	@RpcCommand
	public Map<String, Object> authDevice()
	{
		return null;
	}
	
	
	@RpcCommand(RestrictionType.PUBLIC)
	public Boolean authTransient(RpcMessage msgIn, String email, String password)
	{
		User targetUser = null;
		try{ targetUser = this.dbManager.getUser_byEmail(email); }
		catch( DatabaseManagerException e ) { return Boolean.FALSE; }
		if( targetUser == null ) return Boolean.FALSE;
		
		// if we made it here, we found our user...now hash and check the result
		Boolean retVal = targetUser.getPasswordHash().equals(User.generatePasswordHash(password, targetUser.getPasswordSalt()));
		if( retVal )
		{
			DeviceProxy sourceDp = DeviceProxy.extractSourceDeviceProxy_fromMessageMetaData(msgIn);
			if( sourceDp == null )
			{
				this.logger.warn("message did not have sourceDp, transient auth failed");
				retVal = false;
			}
			else
			{
				this.logger.info(String.format("transient auth successful for '%s'", email));
				sourceDp.setOwner(targetUser);
			}
		}
		return retVal;
	}
	
	
	@RpcCommand
	public List<User> getUserList() throws DatabaseManagerException
	{
		return this.dbManager.getUserList();
	}
	
	
	@RpcCommand
	public List<Group> getGroupList() throws DatabaseManagerException
	{
		return this.dbManager.getGroupList();
	}
	
	
	@RpcCommand
	public void addUser(User user) throws DatabaseManagerException
	{
		this.dbManager.addUser(user);
		this.logger.info(String.format("user added: '%s'", user.getEmail()));
	}
	
	
	@RpcCommand
	public void deleteUserByEmail(String email) throws DatabaseManagerException
	{
		if( !this.dbManager.deleteUserByEmail(email) ) throw RpcException.commandHandlerException("user not found");
		this.logger.info(String.format("user deleted: '%s'", email));
	}
	
	
	@RpcCommand
	public void addGroup(Group group) throws DatabaseManagerException
	{
		this.dbManager.addGroup(group);
		this.logger.info(String.format("group added: '%d::%s'", group.getId(), group.getName()));
	}
	
	
	@RpcCommand
	public void deleteGroupById(Integer id) throws DatabaseManagerException
	{
		if( !this.dbManager.deleteGroupById(id) ) throw RpcException.commandHandlerException("group not found");
		this.logger.info(String.format("group deleted: '%d'", id));
	}
	
	
	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString()
	{
		return String.format("%s.%s", this.getClass().getSimpleName(), System.identityHashCode(this));
	}
}
